package com.hydra.base.controller;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hydra.base.annotations.PageQuery;
import com.hydra.base.dto.BaseQueryDto;
import com.hydra.base.dto.auth.AuthUser;
import com.hydra.base.entity.CodeEntity;
import com.hydra.base.entity.DelFlagInterface;
import com.hydra.base.entity.IdEntity;
import com.hydra.base.entity.UserTimeInterface;
import com.hydra.base.error.BusinessException;
import com.hydra.base.feign.OpenFeignAuthService;
import com.hydra.base.resp.Response;
import com.hydra.base.services.BaseService;
import com.hydra.base.utils.BeanConvertUtils;
import com.hydra.base.utils.JsonUtil;
import com.hydra.base.utils.RequestUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 基本的控制器，负责基本的增删改查功能
 * @Author Hydra
 * @Date 2022/4/29 17:46
 */
@Slf4j
@SuppressWarnings("all")
public abstract class BaseController<DTO extends BaseQueryDto, T extends IdEntity, M extends BaseMapper<T>, S extends BaseService<T, M>> {

    protected S repository;

    public void setRepository(S repository){
        this.repository = repository;
    }

    @Resource
    private OpenFeignAuthService authService;

    /**
     * 匹配查询条件
     * @param wrapper   查询条件
     */
    protected QueryWrapper<T> handleQueryWrapper(QueryWrapper<T> wrapper, DTO params){
        return wrapper;
    }

    /**分页查询*/
    protected IPage<T> pageQuery(IPage<T> page, QueryWrapper<T> queryWrapper, DTO params){
        return this.repository.page(page, queryWrapper);
    }
    /**列表查询*/
    protected List<T> listQuery(QueryWrapper<T> queryWrapper, DTO params){
        return this.repository.list(queryWrapper);
    }

    /**查询数据之后的处理*/
    protected IPage<T> handleAfterSearch(IPage<T> pageResult, DTO params){
        return pageResult;
    }

    /**保存前获取发号器的code，为空表示不需要创建code发号器*/
    protected String getSaveSerialNoCode(){
        return null;
    }

    /**GetById之后的处理*/
    protected T handleAfterGetData(T data){
        return data;
    }

    /**保存之前的处理*/
    protected T handleBeforeSave(T data, T history){
        return data;
    }

    /**保存之后的处理*/
    protected T handleAfterSave(T t, T history, boolean success){
        return t;
    }


    /**删除之前的处理*/
    protected T handleBeforeDelete(T t){
        return t;
    }

    /**删除之后的处理*/
    protected T handleAfterDelete(T t, boolean success){
        return t;
    }

    /**构建查询请求*/
    protected QueryWrapper<T> buildQueryWrapper(@RequestBody DTO params){
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("del_flag", false);
        if(params != null){
            Field[] paramsFields = ReflectUtil.getFields(params.getClass());
            if(ArrayUtil.isNotEmpty(paramsFields)){
                for (Field paramsField : paramsFields) {
                    PageQuery pageQueryAnnotation = paramsField.getAnnotation(PageQuery.class);
                    if(pageQueryAnnotation != null){
                        Object fieldValue = ReflectUtil.getFieldValue(params, paramsField);
                        if(fieldValue != null){
                            //如果是字符串，空串也不需要查询
                            if(fieldValue instanceof String){
                                if(StringUtils.isBlank((String)fieldValue)){
                                    fieldValue = null;
                                }
                            }else if(fieldValue instanceof Collection){
                                if(CollectionUtils.isEmpty((Collection)fieldValue)){
                                    fieldValue = null;
                                }
                            }
                        }
                        if(fieldValue != null){
                            String fieldName = pageQueryAnnotation.entityFieldName();
                            if(StringUtils.isBlank(fieldName)){
                                fieldName = paramsField.getName();
                            }
                            fieldName = StrUtil.toUnderlineCase(fieldName);
                            ReflectUtil.invoke(queryWrapper, pageQueryAnnotation.queryType().getCode(), true, fieldName, fieldValue);
                        }
                    }
                }
            }
        }
        return queryWrapper;
    }

    /**处理创建人、更新人信息*/
    public void handleCreatorInfo(List<T> records){
        if(!CollectionUtils.isEmpty(records)){
            T data = records.get(0);
            if(data instanceof UserTimeInterface){
                Set<String> codeList = new HashSet<>();
                for (T record : records) {
                    UserTimeInterface obj = (UserTimeInterface)record;
                    codeList.add(obj.getCreator());
                    codeList.add(obj.getUpdater());
                }
                //获取用户列表信息
                Response<List<AuthUser>> response = authService.listAuthUserByCodeList(new ArrayList<>(codeList));
                List<AuthUser> authUserList = response.getData();
                if(!CollectionUtils.isEmpty(authUserList)){
                    Map<String, String> map = authUserList.stream().collect(Collectors.toMap(AuthUser::getCode, AuthUser::getName, (a, b) -> a));
                    for (T record : records) {
                        UserTimeInterface obj = (UserTimeInterface)record;
                        String creator = obj.getCreator();
                        if(StringUtils.isNotBlank(creator)){
                            obj.setCreatorName(map.get(creator));
                        }
                        String updater = obj.getUpdater();
                        if(StringUtils.isNotBlank(updater)){
                            obj.setUpdaterName(map.get(updater));
                        }
                    }
                }
            }
        }
    }

    /**
     * 分页查询接口
     * @param params 入参
     * @return      分页对象
     */
    @PostMapping(path = "/page")
    public IPage<T> page(@RequestBody DTO params) {
        QueryWrapper<T> queryWrapper = this.buildQueryWrapper(params);

        int currentPage = 0, pageLimit = 10;
        if(params != null){
            currentPage = params.getPage();
            pageLimit = params.getLimit();
        }

        IPage<T> page = new Page<>(currentPage, pageLimit);

        //处理查询条件
        queryWrapper = this.handleQueryWrapper(queryWrapper, params);

        page = this.pageQuery(page, queryWrapper, params);

        //获取列表
        List<T> records = page.getRecords();

        //处理创建人、更新人信息
        this.handleCreatorInfo(records);

        page = this.handleAfterSearch(page, params);
        return page;
    }

    /**
     * 分页查询接口
     * @param params 入参
     * @return      分页对象
     */
    @PostMapping(path = "/list")
    public List<T> list(@RequestBody DTO params) {
        QueryWrapper<T> queryWrapper = this.buildQueryWrapper(params);

        //list查询限制99条数据
        queryWrapper.last("limit 99");

        //处理查询条件
        queryWrapper = this.handleQueryWrapper(queryWrapper, params);

        List<T> records = this.listQuery(queryWrapper, params);
        //处理创建人、更新人信息
        this.handleCreatorInfo(records);

        return records;
    }

    /**
     * 根据ID查询实体对象
     * @param id id
     * @return 结果实体
     */
    @GetMapping("/getById")
    public T getById(@RequestParam("id") String id){
        T data = this.repository.getById(id);
        data = this.handleAfterGetData(data);
        if(data instanceof UserTimeInterface){
            UserTimeInterface obj = (UserTimeInterface) data;
            ArrayList<String> codeList = new ArrayList<>();
            codeList.add(obj.getCreator());
            codeList.add(obj.getUpdater());
            Response<List<AuthUser>> response = authService.listAuthUserByCodeList(codeList);
            List<AuthUser> authUserList = response.getData();
            Map<String, String> map = authUserList.stream().collect(Collectors.toMap(AuthUser::getCode, AuthUser::getName, (a, b) -> a));
            obj.setCreatorName(map.get(obj.getCreator()));
            obj.setUpdaterName(map.get(obj.getUpdater()));
        }
        return data;
    }


    /**
     * 新增或修改
     * @param data 实体对象
     */
    @Transactional(rollbackFor=Exception.class)
    @PostMapping(path = "/save")
    public T save(@RequestBody T data){
        if(data == null){
            throw new BusinessException("保存对象不能为空！");
        }
        try {
            Long id = data.getId();
            T history = null;
            if(id != null){
                history = repository.getById(id);
            }
            return handleSave(data, history);
        } catch (Exception e) {
            //手动回滚事务，打印info日志
            log.info("新增或保存数据失败：{}", e.getMessage(), e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new BusinessException(e.getMessage());
        }
    }



    /**
     * 新增或修改
     * @param data 实体对象
     */
    @Transactional(rollbackFor=Exception.class)
    @PostMapping(path = "/saveNoNull")
    public T saveNoNull(@RequestBody T data){
        if(data == null){
            throw new BusinessException("保存对象不能为空！");
        }
        try {
            Long id = data.getId();
            T history = null;
            if(id != null){
                history = repository.getById(id);
                if(history != null){
                    T temp = (T)data.getClass().newInstance();
                    BeanConvertUtils.copyProperties(history, temp);
                    BeanConvertUtils.copyPropertiesWithoutNull(data, temp);
                    data = temp;
                }
            }
            return handleSave(data, history);
        } catch (Exception e) {
            //手动回滚事务，打印info日志
            log.info("新增或保存数据失败：{}", e.getMessage(), e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new BusinessException(e.getMessage());
        }
    }

    private T handleSave(T data, T history){
        //处理日期
        if(data instanceof UserTimeInterface){
            //获取创建人
            AuthUser authUser = RequestUtils.getAuthUser();
            if(authUser != null){
                UserTimeInterface userTimeEntity = (UserTimeInterface) data;
                if(StringUtils.isBlank(userTimeEntity.getCreator())){
                    userTimeEntity.setCreator(authUser.getCode());
                    userTimeEntity.setCreateTime(LocalDateTime.now());
                }
                userTimeEntity.setUpdater(authUser.getCode());
                userTimeEntity.setUpdateTime(LocalDateTime.now());
            }
        }

        //处理code，如果id和history为null，且code为空，说明需要生成code
        if(data instanceof CodeEntity){
            String serialNoCode = this.getSaveSerialNoCode();
            if(StringUtils.isNotBlank(serialNoCode)){
                if(data.getId() == null && history == null && StringUtils.isBlank(((CodeEntity) data).getCode())){
                    //生成code
                    Response<String> generateSerialNoCodeResp = authService.generateSerialNoCode(serialNoCode);
                    if(generateSerialNoCodeResp != null && generateSerialNoCodeResp.isSuccess()){
                        ((CodeEntity) data).setCode(generateSerialNoCodeResp.getData());
                    }else{
                        log.error("获取发号器code失败，type：{}，返回内容：{}", serialNoCode, JsonUtil.toJsonString(generateSerialNoCodeResp));
                    }
                }
            }
        }

        data = handleBeforeSave(data, history);

        //记录操作日志
        repository.handleOperateLog(data, history);

        boolean success = repository.saveOrUpdate(data);
        return handleAfterSave(data, history, success);
    }


    /**
     * 根据id删除对象
     * @param t 实体对象
     */
    @Transactional(rollbackFor=Exception.class)
    @PostMapping(path = "/delete")
    public T delete(@RequestBody T t){
        try {
            Long id = t.getId();
            if(id != null){
                T entity = repository.getById(id);
                entity = handleBeforeDelete(entity);
                boolean success = false;
                if(entity != null){
                    if(t instanceof DelFlagInterface){
                        UpdateWrapper<T> wrapper = new UpdateWrapper<T>()
                                .set("del_flag", true)
                                .eq("id", id);
                        success = repository.update(wrapper);
                    }else{
                        success = repository.removeById(id);
                    }
                }
                t = handleAfterDelete(entity, success);
            }
            return t;
        } catch (BusinessException e) {
            //手动回滚事务，打印info日志
            log.info("删除数据失败：{}", e.getMessage(), e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new BusinessException(e.getMessage());
        }
    }


}
